﻿namespace dot_in.HTWKAidStation.Client.Timetable
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Text.RegularExpressions;
    using System.Threading.Tasks;

    public static class TimetableParser
    {
        public static List<EventDay> GetAllEvents(string html)
        {
            return new List<EventDay>(SplitDays(html).Select(ParseDay).Where(c => c.Events.Count > 0));
        }

        public static List<Week> GetAllWeeks(string xml)
        {
            return ParseWeeks(FilterWeeksXml(xml));
        }

        public static List<Faculty> GetAllFaculties(string xml)
        {
            return Regex.Matches(xml, "<fakultaet name=" + '"' + "([^" + '"' + "]+)" + '"' + "[^>]+>(.+?)(?=</fakultaet>)</fakultaet>", RegexOptions.Singleline).Cast<Match>().Select(match => ParseFaculty(match.Groups[1].Value, match.Groups[2].Value)).ToList();
        }

        private static Faculty ParseFaculty(string name, string xml)
        {
            Faculty result = new Faculty(name);
            foreach (Course course in ParseCourses(xml))
            {
                result.Courses.Add(course);
            }

            return result;
        }

        private static IEnumerable<Course> ParseCourses(string xml)
        {
            return Regex.Matches(xml, "<studiengang name=" + '"' + "([^" + '"' + "]+)" + '"' + "[^>]+>(.+?)(?=</studiengang>)</studiengang>", RegexOptions.Singleline).Cast<Match>().Select(match => new Course(match.Groups[1].Value, ParseTutorialGroup(match.Groups[2].Value))).ToList();
        }

        private static IEnumerable<TutorialGroup> ParseTutorialGroup(string xml)
        {
            return Regex.Matches(xml, "<semgrp name=" + '"' + "([^" + '"' + "]+)" + '"' + " id=" + '"' + "([^" + '"' + "]+)" + '"', RegexOptions.Singleline).Cast<Match>().Select(match => new TutorialGroup(match.Groups[1].Value, match.Groups[2].Value)).ToList();
        }

        private static string FilterWeeksXml(string xml)
        {
            return Regex.Match(xml, @"<period[^>]+>(.+)(?=</period>)", RegexOptions.Singleline).Groups[1].Value;
        }

        private static List<Week> ParseWeeks(string filteredXml)
        {
            return Regex.Matches(filteredXml, "<woche name=" + '"' + "([^" + '"' + "]+)" + '"' + " id=" + '"' + "([^" + '"' + "]+)" + '"', RegexOptions.Singleline).Cast<Match>().Select(match => new Week(match.Groups[1].Value, match.Groups[2].Value)).ToList();
        }

        private static IEnumerable<string> SplitDays(string html)
        {
            List<string> result = new List<string>();
            Match match = Regex.Match(html, @"<p><span >(..)</span></p>");
            html = html.Substring(match.Index, html.Length - match.Index);
            match = Regex.Match(html, @"<p><span >(..)</span></p>");
            match.NextMatch();
            match.NextMatch();
            while (match.Success)
            {
                result.Add(html.Substring(0, match.Index));
                html = html.Substring(match.Index, html.Length - match.Index);
                match = Regex.Match(html, @"<p><span >(..)</span></p>");
                match = match.NextMatch();
            }

            return result.Where(c => c.Length > 0);
        }

        private static EventDay ParseDay(string html)
        {
            EventDay day = new EventDay { DateString = Regex.Match(html, @"<p><span >(..)</span></p>").Groups[1].Value };
            foreach (Match match in Regex.Matches(html, @"<tr>.+?<td>(\d[^<]+)</td>.+?<td>([^<]+)</td>.+?<td>([^<]+)</td>.+?<td>([^<]+)</td>.+?<td>([^<]+)</td>.+?<td>([^<]+)</td>.+?<td>([^<]+)</td>.+?<td>([^<]+)</td>.+?<td>([^<]+)</td>.+?</tr>", RegexOptions.Singleline))
            {
                day.Events.Add(
                    new Event
                        {
                            Description = match.Groups[5].Value,
                            EndTimeString = match.Groups[3].Value,
                            EventType = match.Groups[6].Value,
                            HappeningWeeks = ParseHappeningWeeks(match.Groups[1].Value),
                            HostName = match.Groups[7].Value,
                            Note = match.Groups[8].Value,
                            Room = match.Groups[4].Value,
                            StartTimeString = match.Groups[2].Value
                        });
            }

            return day;
        }

        private static List<int> ParseHappeningWeeks(string value)
        {
            return Regex.Matches(value, @"(\d+)").Cast<Match>().Select(match => int.Parse(match.Value)).ToList();
        }
    }
}
